home *** CD-ROM | disk | FTP | other *** search
/ SGI Freeware 1999 August / SGI Freeware 1999 August.iso / dist / samba.idb / usr / samba / src / source / quotas.c.z / quotas.c
Encoding:
C/C++ Source or Header  |  1998-10-28  |  15.8 KB  |  667 lines

  1. #ifdef QUOTAS
  2. /* 
  3.    Unix SMB/Netbios implementation.
  4.    Version 1.9.
  5.    support for quotas
  6.    Copyright (C) Andrew Tridgell 1992-1998
  7.    
  8.    This program is free software; you can redistribute it and/or modify
  9.    it under the terms of the GNU General Public License as published by
  10.    the Free Software Foundation; either version 2 of the License, or
  11.    (at your option) any later version.
  12.    
  13.    This program is distributed in the hope that it will be useful,
  14.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16.    GNU General Public License for more details.
  17.    
  18.    You should have received a copy of the GNU General Public License
  19.    along with this program; if not, write to the Free Software
  20.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21. */
  22.  
  23.  
  24. /* 
  25.  * This is one of the most system dependent parts of Samba, and its
  26.  * done a litle differently. Each system has its own way of doing 
  27.  * things :-(
  28.  */
  29.  
  30. #include "includes.h"
  31.  
  32. extern int DEBUGLEVEL;
  33.  
  34. #ifdef LINUX
  35.  
  36. #include <sys/types.h>
  37. #include <asm/types.h>
  38. #include <sys/quota.h>
  39.  
  40. #include <mntent.h>
  41. #include <linux/unistd.h>
  42.  
  43. _syscall4(int, quotactl, int, cmd, const char *, special, int, id, caddr_t, addr);
  44.  
  45. /****************************************************************************
  46. try to get the disk space from disk quotas (LINUX version)
  47. ****************************************************************************/
  48.  
  49. BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize)
  50. {
  51.   uid_t euser_id;
  52.   int r;
  53.   struct dqblk D;
  54.   struct stat S;
  55.   FILE *fp;
  56.   struct mntent *mnt;
  57.   int devno;
  58.   int found;
  59.   
  60.   /* find the block device file */
  61.   
  62.   if ( stat(path, &S) == -1 ) {
  63.     return(False) ;
  64.   }
  65.  
  66.   devno = S.st_dev ;
  67.   
  68.   fp = setmntent(MOUNTED,"r");
  69.   found = False ;
  70.   
  71.   while ((mnt = getmntent(fp))) {
  72.     if ( stat(mnt->mnt_dir,&S) == -1 )
  73.       continue ;
  74.     if (S.st_dev == devno) {
  75.       found = True ;
  76.       break ;
  77.     }
  78.   }
  79.   endmntent(fp) ;
  80.   
  81.   if (!found) {
  82.       return(False);
  83.     }
  84.  
  85.   euser_id=geteuid();
  86.   seteuid(0);  
  87.   r=quotactl(QCMD(Q_GETQUOTA,USRQUOTA), mnt->mnt_fsname, euser_id, (caddr_t)&D);
  88.       seteuid(euser_id);
  89.  
  90.   /* Use softlimit to determine disk space, except when it has been exceeded */
  91.   *bsize = 1024;
  92.   if (r)
  93.     {
  94.       if (errno == EDQUOT) 
  95.        {
  96.          *dfree =0;
  97.          *dsize =D.dqb_curblocks;
  98.          return (True);
  99.     }
  100.       else return(False);
  101.   }
  102.   /* Use softlimit to determine disk space, except when it has been exceeded */
  103.   if (
  104.       (D.dqb_bsoftlimit && D.dqb_curblocks>=D.dqb_bsoftlimit) ||
  105.       (D.dqb_bhardlimit && D.dqb_curblocks>=D.dqb_bhardlimit) ||
  106.       (D.dqb_isoftlimit && D.dqb_curinodes>=D.dqb_isoftlimit) ||
  107.       (D.dqb_ihardlimit && D.dqb_curinodes>=D.dqb_ihardlimit)
  108.      )
  109.     {
  110.       *dfree = 0;
  111.       *dsize = D.dqb_curblocks;
  112.     }
  113.   else if (D.dqb_bsoftlimit==0 && D.dqb_bhardlimit==0)
  114.     {
  115.       return(False);
  116.     }
  117.   else {
  118.     if (D.dqb_bsoftlimit == 0)
  119.       D.dqb_bsoftlimit = D.dqb_bhardlimit;
  120.     *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
  121.     *dsize = D.dqb_bsoftlimit;
  122.   }
  123.   return (True);
  124. }
  125.  
  126. #elif defined(CRAY)
  127.  
  128. #include <sys/quota.h>
  129. #include <mntent.h>
  130.  
  131. /****************************************************************************
  132. try to get the disk space from disk quotas (CRAY VERSION)
  133. ****************************************************************************/
  134. BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize)
  135. {
  136.   struct mntent *mnt;
  137.   FILE *fd;
  138.   struct stat sbuf;
  139.   dev_t devno ;
  140.   static dev_t devno_cached = 0 ;
  141.   static pstring name;
  142.   struct q_request request ;
  143.   struct qf_header header ;
  144.   static int quota_default = 0 ;
  145.   int found ;
  146.   
  147.   if ( stat(path,&sbuf) == -1 )
  148.     return(False) ;
  149.   
  150.   devno = sbuf.st_dev ;
  151.   
  152.   if ( devno != devno_cached ) {
  153.     
  154.     devno_cached = devno ;
  155.     
  156.     if ((fd = setmntent(KMTAB)) == NULL)
  157.       return(False) ;
  158.     
  159.     found = False ;
  160.     
  161.     while ((mnt = getmntent(fd)) != NULL) {
  162.       
  163.       if ( stat(mnt->mnt_dir,&sbuf) == -1 )
  164.     continue ;
  165.       
  166.       if (sbuf.st_dev == devno) {
  167.     
  168.     found = True ;
  169.     break ;
  170.     
  171.       }
  172.       
  173.     }
  174.     
  175.     pstrcpy(name,mnt->mnt_dir) ;
  176.     endmntent(fd) ;
  177.     
  178.     if ( ! found )
  179.       return(False) ;
  180.   }
  181.   
  182.   request.qf_magic = QF_MAGIC ;
  183.   request.qf_entry.id = geteuid() ;
  184.   
  185.   if (quotactl(name, Q_GETQUOTA, &request) == -1)
  186.     return(False) ;
  187.   
  188.   if ( ! request.user )
  189.     return(False) ;
  190.   
  191.   if ( request.qf_entry.user_q.f_quota == QFV_DEFAULT ) {
  192.     
  193.     if ( ! quota_default ) {
  194.       
  195.       if ( quotactl(name, Q_GETHEADER, &header) == -1 )
  196.     return(False) ;
  197.       else
  198.     quota_default = header.user_h.def_fq ;
  199.     }
  200.     
  201.     *dfree = quota_default ;
  202.     
  203.   }else if ( request.qf_entry.user_q.f_quota == QFV_PREVENT ) {
  204.     
  205.     *dfree = 0 ;
  206.     
  207.   }else{
  208.     
  209.     *dfree = request.qf_entry.user_q.f_quota ;
  210.     
  211.   }
  212.   
  213.   *dsize = request.qf_entry.user_q.f_use ;
  214.   
  215.   if ( *dfree )
  216.     *dfree -= *dsize ;
  217.   
  218.   if ( *dfree < 0 )
  219.     *dfree = 0 ;
  220.   
  221.   *bsize = 4096 ;  /* Cray blocksize */
  222.   
  223.   return(True) ;
  224.   
  225. }
  226.  
  227.  
  228. #elif defined(SUNOS5) || defined(SUNOS4)
  229.  
  230. #include <fcntl.h>
  231. #if defined(SUNOS5)
  232. #include <sys/fs/ufs_quota.h>
  233. #include <sys/mnttab.h>
  234. #else /* defined(SUNOS4) */
  235. #include <ufs/quota.h>
  236. #include <mntent.h>
  237. #endif
  238.  
  239. /****************************************************************************
  240. try to get the disk space from disk quotas (solaris 2 version)
  241. ****************************************************************************/
  242. /* Quota code by Peter Urbanec (amiga@cse.unsw.edu.au) */
  243. BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize)
  244. {
  245.   uid_t user_id, euser_id;
  246.   int ret;
  247.   struct dqblk D;
  248. #if defined(SUNOS5)
  249.   struct quotctl command;
  250.   int file;
  251.   struct mnttab mnt;
  252.   static pstring name;
  253. #else
  254.   struct mntent *mnt;
  255.   static pstring name;
  256. #endif
  257.   FILE *fd;
  258.   struct stat sbuf;
  259.   dev_t devno ;
  260.   static dev_t devno_cached = 0 ;
  261.   int found ;
  262.   
  263.   if ( stat(path,&sbuf) == -1 )
  264.     return(False) ;
  265.   
  266.   devno = sbuf.st_dev ;
  267.   DEBUG(5,("disk_quotas: looking for path \"%s\" devno=%o\n", path,devno));
  268.   if ( devno != devno_cached ) {
  269.     devno_cached = devno ;
  270. #if defined(SUNOS5)
  271.     if ((fd = fopen(MNTTAB, "r")) == NULL)
  272.       return(False) ;
  273.     
  274.     found = False ;
  275.     while (getmntent(fd, &mnt) == 0) {
  276.       if ( stat(mnt.mnt_mountp,&sbuf) == -1 )
  277.     continue ;
  278.       DEBUG(5,("disk_quotas: testing \"%s\" devno=%o\n", 
  279.            mnt.mnt_mountp,sbuf.st_dev));
  280.       if (sbuf.st_dev == devno) {
  281.     found = True ;
  282.     break ;
  283.       }
  284.     }
  285.     
  286.     pstrcpy(name,mnt.mnt_mountp) ;
  287.     pstrcat(name,"/quotas") ;
  288.     fclose(fd) ;
  289. #else
  290.     if ((fd = setmntent(MOUNTED, "r")) == NULL)
  291.       return(False) ;
  292.     
  293.     found = False ;
  294.     while ((mnt = getmntent(fd)) != NULL) {
  295.       if ( stat(mnt->mnt_dir,&sbuf) == -1 )
  296.     continue ;
  297.       DEBUG(5,("disk_quotas: testing \"%s\" devno=%o\n", 
  298.            mnt->mnt_dir,sbuf.st_dev));
  299.       if (sbuf.st_dev == devno) {
  300.     found = True ;
  301.     break ;
  302.       }
  303.     }
  304.     
  305.     pstrcpy(name,mnt->mnt_fsname) ;
  306.     endmntent(fd) ;
  307. #endif
  308.     
  309.     if ( ! found )
  310.       return(False) ;
  311.   }
  312.  
  313.   euser_id = geteuid();
  314.   user_id = getuid();
  315.  
  316.   setuid(0);  /* Solaris seems to want to give info only to super-user */
  317.   seteuid(0);
  318.  
  319. #if defined(SUNOS5)
  320.   DEBUG(5,("disk_quotas: looking for quotas file \"%s\"\n", name));
  321.   if((file=open(name, O_RDONLY))<0) {
  322.     setuid(user_id);  /* Restore the original UID status */
  323.     seteuid(euser_id);
  324.     return(False);
  325.   }
  326.   command.op = Q_GETQUOTA;
  327.   command.uid = euser_id;
  328.   command.addr = (caddr_t) &D;
  329.   ret = ioctl(file, Q_QUOTACTL, &command);
  330.   close(file);
  331. #else
  332.   DEBUG(5,("disk_quotas: trying quotactl on device \"%s\"\n", name));
  333.   ret = quotactl(Q_GETQUOTA, name, euser_id, &D);
  334. #endif
  335.  
  336.   setuid(user_id); /* Restore the original uid status. */
  337.   seteuid(euser_id);
  338.  
  339.   if (ret < 0) {
  340.     DEBUG(2,("disk_quotas ioctl (Solaris) failed\n"));
  341.     return(False);
  342.   }
  343.  
  344.  
  345.   /* Use softlimit to determine disk space. A user exceeding the quota is told
  346.    * that there's no space left. Writes might actually work for a bit if the
  347.    * hardlimit is set higher than softlimit. Effectively the disk becomes
  348.    * made of rubber latex and begins to expand to accommodate the user :-)
  349.    */
  350.  
  351.   if (D.dqb_bsoftlimit==0)
  352.     return(False);
  353.   *bsize = 512;
  354.   *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
  355.   *dsize = D.dqb_bsoftlimit;
  356.   if(*dfree < 0)
  357.     {
  358.      *dfree = 0;
  359.      *dsize = D.dqb_curblocks;
  360.     }
  361.       
  362. DEBUG(5,("disk_quotas for path \"%s\" returning  bsize %d, dfree %d, dsize %d\n",
  363.          path,*bsize,*dfree,*dsize));
  364.  
  365.       return(True);
  366. }
  367.  
  368.  
  369. #elif defined(OSF1)
  370. #include <ufs/quota.h>
  371.  
  372. /****************************************************************************
  373. try to get the disk space from disk quotas - OFS1 version
  374. ****************************************************************************/
  375. BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize)
  376. {
  377.   uid_t user_id, euser_id;
  378.   int r, save_errno;
  379.   struct dqblk D;
  380.   struct stat S;
  381.  
  382.   euser_id = geteuid();
  383.   user_id = getuid();
  384.  
  385.   setreuid(euser_id, -1);
  386.   r= quotactl(path,QCMD(Q_GETQUOTA, USRQUOTA),euser_id,(char *) &D);
  387.   if (r)
  388.      save_errno = errno;
  389.  
  390.   if (setreuid(user_id, -1) == -1)
  391.     DEBUG(5,("Unable to reset uid to %d\n", user_id));
  392.  
  393.   *bsize = DEV_BSIZE;
  394.  
  395.   if (r)
  396.   {
  397.       if (save_errno == EDQUOT)   // disk quota exceeded
  398.       {
  399.          *dfree = 0;
  400.          *dsize = D.dqb_curblocks;
  401.          return (True);
  402.       }
  403.       else
  404.          return (False);  
  405.   }
  406.  
  407.   /* Use softlimit to determine disk space, except when it has been exceeded */
  408.  
  409.   if (D.dqb_bsoftlimit==0)
  410.     return(False);
  411.  
  412.   if ((D.dqb_curblocks>D.dqb_bsoftlimit)) {
  413.     *dfree = 0;
  414.     *dsize = D.dqb_curblocks;
  415.   } else {
  416.     *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
  417.     *dsize = D.dqb_bsoftlimit;
  418.   }
  419.   return (True);
  420. }
  421.  
  422. #elif defined (SGI6)
  423. /****************************************************************************
  424. try to get the disk space from disk quotas (IRIX 6.2 version)
  425. ****************************************************************************/
  426.  
  427. #include <sys/quota.h>
  428. #include <mntent.h>
  429.  
  430. BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize)
  431. {
  432.   uid_t euser_id;
  433.   int r;
  434.   struct dqblk D;
  435.   struct fs_disk_quota        F;
  436.   struct stat S;
  437.   FILE *fp;
  438.   struct mntent *mnt;
  439.   int devno;
  440.   int found;
  441.   
  442.   /* find the block device file */
  443.   
  444.   if ( stat(path, &S) == -1 ) {
  445.     return(False) ;
  446.   }
  447.  
  448.   devno = S.st_dev ;
  449.   
  450.   fp = setmntent(MOUNTED,"r");
  451.   found = False ;
  452.   
  453.   while ((mnt = getmntent(fp))) {
  454.     if ( stat(mnt->mnt_dir,&S) == -1 )
  455.       continue ;
  456.     if (S.st_dev == devno) {
  457.       found = True ;
  458.       break ;
  459.     }
  460.   }
  461.   endmntent(fp) ;
  462.   
  463.   if (!found) {
  464.     return(False);
  465.   }
  466.  
  467.   euser_id=geteuid();
  468.   seteuid(0);  
  469.  
  470.   /* Use softlimit to determine disk space, except when it has been exceeded */
  471.  
  472.   *bsize = 512;
  473.  
  474.   if ( 0 == strcmp ( mnt->mnt_type, "efs" ))
  475.   {
  476.     r=quotactl (Q_GETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &D);
  477.  
  478.     seteuid(euser_id); /* Restore the original uid status. */
  479.  
  480.     if (r==-1)
  481.       return(False);
  482.         
  483.     /* Use softlimit to determine disk space, except when it has been exceeded */
  484.     if (
  485.         (D.dqb_bsoftlimit && D.dqb_curblocks>=D.dqb_bsoftlimit) ||
  486.         (D.dqb_bhardlimit && D.dqb_curblocks>=D.dqb_bhardlimit) ||
  487.         (D.dqb_fsoftlimit && D.dqb_curfiles>=D.dqb_fsoftlimit) ||
  488.         (D.dqb_fhardlimit && D.dqb_curfiles>=D.dqb_fhardlimit)
  489.        )
  490.     {
  491.       *dfree = 0;
  492.       *dsize = D.dqb_curblocks;
  493.     }
  494.     else if (D.dqb_bsoftlimit==0 && D.dqb_bhardlimit==0)
  495.     {
  496.       return(False);
  497.     }
  498.     else 
  499.     {
  500.       *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
  501.       *dsize = D.dqb_bsoftlimit;
  502.     }
  503.  
  504.   }
  505.   else if ( 0 == strcmp ( mnt->mnt_type, "xfs" ))
  506.   {
  507.     r=quotactl (Q_XGETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &F);
  508.  
  509.     seteuid(euser_id); /* Restore the original uid status. */
  510.  
  511.     if (r==-1)
  512.       return(False);
  513.         
  514.     /* Use softlimit to determine disk space, except when it has been exceeded */
  515.     if (
  516.         (F.d_blk_softlimit && F.d_bcount>=F.d_blk_softlimit) ||
  517.         (F.d_blk_hardlimit && F.d_bcount>=F.d_blk_hardlimit) ||
  518.         (F.d_ino_softlimit && F.d_icount>=F.d_ino_softlimit) ||
  519.         (F.d_ino_hardlimit && F.d_icount>=F.d_ino_hardlimit)
  520.        )
  521.     {
  522.       /*
  523.        * Fixme!: these are __uint64_t, this may truncate values
  524.        */
  525.       *dfree = 0;
  526.       *dsize = (int) F.d_bcount;
  527.     }
  528.     else if (F.d_blk_softlimit==0 && F.d_blk_hardlimit==0)
  529.     {
  530.       return(False);
  531.     }
  532.     else 
  533.     {
  534.       *dfree = (int)(F.d_blk_softlimit - F.d_bcount);
  535.       *dsize = (int)F.d_blk_softlimit;
  536.     }
  537.  
  538.   }
  539.   else
  540.   {
  541.     seteuid(euser_id); /* Restore the original uid status. */
  542.     return(False);
  543.   }
  544.  
  545.   return (True);
  546.  
  547. }
  548.  
  549. #else
  550.  
  551. #if    defined(__FreeBSD__) || defined(__OpenBSD__)
  552. #include <ufs/ufs/quota.h>
  553. #include <machine/param.h>
  554. #elif         AIX
  555. /* AIX quota patch from Ole Holm Nielsen <ohnielse@fysik.dtu.dk> */
  556. #include <jfs/quota.h>
  557. /* AIX 4.X: Rename members of the dqblk structure (ohnielse@fysik.dtu.dk) */
  558. #define dqb_curfiles dqb_curinodes
  559. #define dqb_fhardlimit dqb_ihardlimit
  560. #define dqb_fsoftlimit dqb_isoftlimit
  561. #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ */
  562. #include <sys/quota.h>
  563. #include <devnm.h>
  564. #endif
  565.  
  566. /****************************************************************************
  567. try to get the disk space from disk quotas - default version
  568. ****************************************************************************/
  569. BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize)
  570. {
  571.   uid_t euser_id;
  572.   int r;
  573.   struct dqblk D;
  574. #if !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__)
  575.   char dev_disk[256];
  576.   struct stat S;
  577.   /* find the block device file */
  578.   if ((stat(path, &S)<0) ||
  579.       (devnm(S_IFBLK, S.st_dev, dev_disk, 256, 0)<0)) return (False);
  580. #endif
  581.  
  582.   euser_id = geteuid();
  583.  
  584. #ifdef USE_SETRES
  585.   {
  586.     uid_t user_id;
  587.  
  588.     /* for HPUX, real uid must be same as euid to execute quotactl for euid */
  589.     user_id = getuid();
  590.     setresuid(euser_id,-1,-1);
  591.     r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
  592.     if (setresuid(user_id,-1,-1))
  593.       DEBUG(5,("Unable to reset uid to %d\n", user_id));
  594.   }
  595. #else /* USE_SETRES */
  596. #if defined(__FreeBSD__) || defined(__OpenBSD__)
  597.   {
  598.     /* FreeBSD patches from Marty Moll <martym@arbor.edu> */
  599.     uid_t user_id;
  600.     gid_t egrp_id;
  601.  
  602.     /* Need to be root to get quotas in FreeBSD */
  603.     user_id = getuid();
  604.     egrp_id = getegid();
  605.     setuid(0);
  606.     seteuid(0);
  607.     r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
  608.  
  609.     /* As FreeBSD has group quotas, if getting the user
  610.        quota fails, try getting the group instead. */
  611.     if (r)
  612.       r= quotactl(path,QCMD(Q_GETQUOTA,GRPQUOTA),egrp_id,(char *) &D);
  613.     setuid(user_id);
  614.     seteuid(euser_id);
  615.   }
  616. #elif defined(AIX)
  617.   /* AIX has both USER and GROUP quotas: 
  618.      Get the USER quota (ohnielse@fysik.dtu.dk) */
  619.   r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
  620. #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ */
  621.   r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
  622. #endif /* !__FreeBSD__ && !AIX && !__OpenBSD__ */
  623. #endif /* USE_SETRES */
  624.  
  625.   /* Use softlimit to determine disk space, except when it has been exceeded */
  626. #if defined(__FreeBSD__) || defined(__OpenBSD__)
  627.   *bsize = DEV_BSIZE;
  628. #else /* !__FreeBSD__ && !__OpenBSD__ */
  629.   *bsize = 1024;
  630. #endif /*!__FreeBSD__ && !__OpenBSD__ */
  631.  
  632.   if (r)
  633.     {
  634.       if (errno == EDQUOT) 
  635.     {
  636.        *dfree =0;
  637.        *dsize =D.dqb_curblocks;
  638.        return (True);
  639.     }
  640.       else return(False);
  641.     }
  642.   if (D.dqb_bsoftlimit==0)
  643.     return(False);
  644.   /* Use softlimit to determine disk space, except when it has been exceeded */
  645.   if ((D.dqb_curblocks>D.dqb_bsoftlimit)
  646. #if !defined(__FreeBSD__) && !defined(__OpenBSD__)
  647. ||((D.dqb_curfiles>D.dqb_fsoftlimit) && (D.dqb_fsoftlimit != 0))
  648. #endif
  649.     ) {
  650.       *dfree = 0;
  651.       *dsize = D.dqb_curblocks;
  652.     }
  653.   else {
  654.     *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
  655.     *dsize = D.dqb_bsoftlimit;
  656.   }
  657.   return (True);
  658. }
  659.  
  660. #endif
  661.  
  662. #else
  663. /* this keeps fussy compilers happy */
  664.  void quotas_dummy(void) {}
  665. #endif /* QUOTAS */
  666.  
  667.